package org.jeecg.common.rc.permition.datapermition;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
import org.jeecg.common.rc.permition.datapermition.anno.ex_anno.CustomPermission;
import org.jeecg.common.rc.permition.datapermition.anno.sys_anno.DeptPermission;
import org.jeecg.common.rc.permition.datapermition.anno.sys_anno.IgnorePermission;
import org.jeecg.common.rc.permition.datapermition.anno.sys_anno.RolePermission;
import org.jeecg.common.rc.permition.datapermition.expression_handler.CustomPermitionHandler;
import org.jeecg.common.rc.permition.datapermition.expression_handler.DepartPermitionHandler;
import org.jeecg.common.rc.permition.datapermition.expression_handler.RolePermitionHandler;
import org.jeecg.common.util.JlStrUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.HexValue;
import net.sf.jsqlparser.schema.Column;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotatedElementUtils;

import java.lang.reflect.Method;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;

/**
 * @author zjarlin
 */
@Configuration
@Slf4j
public class DataPermissionHandlerImpl implements DataPermissionHandler {

    /**
     * 构建Column
     *
     * @param tableAlias 表别名
     * @param columnName 字段名称
     * @return 带表别名字段
     */
    public static Column buildColumn(String tableAlias, String columnName) {
        if (StringUtils.isNotEmpty(tableAlias)) {
            columnName = tableAlias + "." + columnName;
        }
        return new Column(columnName);
    }



    @Override
    @SneakyThrows
    public Expression getSqlSegment(Expression where, String mappedStatementId) {
        where = Optional.ofNullable(where).orElse(new HexValue(" 1 = 1 "));
        //系统包排除
        if (StrUtil.startWith(mappedStatementId,"org.jeecg.modules.system")) {
            return where;
        }

        log.info("开始进行权限过滤,where: {},mappedStatementId: {}", where, mappedStatementId);
        //获取mapper名称
        String mapperClassRef = mappedStatementId.substring(0, mappedStatementId.lastIndexOf("."));
        //获取方法名
        String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(".") + 1);

        //获取实体文件名
        String objectName = StrUtil.subBetween(mapperClassRef, "mapper.", "Mapper");
        //获取service文件名
        String serviceName = StrUtil.addSuffixIfNot(objectName, "Service");
        String iServiceName = StrUtil.addPrefixIfNot(serviceName, "I");
        //获取controller文件名
        String controllerName = StrUtil.addSuffixIfNot(objectName, "Controller");
        //获取上上级crud目录
        String pathFromRight = JlStrUtil.getPathFromRight(mapperClassRef, 2);
        //获取controller引用
        String controllerRef = StrUtil.join(".", pathFromRight, "controller", controllerName);
        String serviceRef = StrUtil.join(".", pathFromRight, "service", serviceName);
        String iServiceRef = StrUtil.join(".", pathFromRight, "service", iServiceName);
        //获取service引用


//       获取controller引用
        //获取当前mapper 的方法
        Class<?> mapperClass = null;
        Class<?> controllerClass = null;
        Class<?> serviceClass = null;
        try {
            mapperClass = Class.forName(mapperClassRef);
        } catch (ClassNotFoundException e) {
            return where;
        }
        try {
            controllerClass = Class.forName(controllerRef);
        } catch (ClassNotFoundException e) {
            return where;
        }
        try {
            serviceClass = Class.forName(serviceRef);
        } catch (ClassNotFoundException e) {
            try {
                serviceClass = Class.forName(iServiceRef);
            } catch (ClassNotFoundException ex) {
                return where;
            }
        }

        Method[] controllerMethods = controllerClass.getMethods();
//        Method[] serviceMethods = serviceClass.getMethods();
//        Method[] mapperMethods = mapperClass.getMethods();

        final Expression finalWhere = where;
        Expression expression1 = Stream.of(controllerMethods)
//        .flatMap(e -> Arrays.stream(e))
                .filter(m -> {
                    boolean annotated = AnnotatedElementUtils.isAnnotated(m, CustomPermission.class);
                    boolean annotated1 = AnnotatedElementUtils.isAnnotated(m, DeptPermission.class);
                    boolean annotated2 = AnnotatedElementUtils.isAnnotated(m, RolePermission.class);
                    boolean annotated3 = !AnnotatedElementUtils.isAnnotated(m, IgnorePermission.class);
                    return annotated3&&(annotated || annotated1 || annotated2);
                }).map(m -> {

                    Set<CustomPermission> as = AnnotatedElementUtils.findMergedRepeatableAnnotations(m, CustomPermission.class); //boolean annotationPresent = m.isAnnotationPresent(CustomPermission.class);

                    CustomPermission customPermission = m.getAnnotation(CustomPermission.class);
//                    CustomPermission.List customPermissions = m.getAnnotation(CustomPermission.List.class);

//                    Optional<CustomPermission> declaredAnnotation = Optional.ofNullable(customPermission);
//                    Optional<CustomPermission[]> dictCode2Names = Optional.ofNullable(customPermissions).map(CustomPermission.List::value);
//                    List<CustomPermission> as = declaredAnnotation.map(Arrays::asList).orElseGet(() -> dictCode2Names.map(Arrays::stream).orElseGet(Stream::empty).collect(Collectors.toList()));
                    //多个可重复自定义权限追加
                    Expression cusAdded = as.size() == 1
                            ? new CustomPermitionHandler().addPermition(finalWhere, customPermission)
                            : as.stream()
                            .map(cusAnno -> {
                                Expression expression = new CustomPermitionHandler().addPermition(finalWhere, cusAnno);
                                return Pair.of(cusAnno, expression);
                            })
                            .reduce((curr, next) -> {
                                CustomPermission cusCurr = curr.getLeft();
                                Expression expCurr = curr.getRight();
                                CustomPermission nextCurr = next.getLeft();
                                Expression nextExp = next.getRight();
                                Expression expression = new CustomPermitionHandler().addPermition(expCurr, nextCurr);
                                return Pair.of(nextCurr, expression);
                            }).orElse(Pair.of(customPermission, finalWhere)).getRight();

                    RolePermission rolePermission = m.getAnnotation(RolePermission.class);
                    Expression roleAdded = new RolePermitionHandler().addPermition(cusAdded, rolePermission);
                    DeptPermission deptPermission = m.getAnnotation(DeptPermission.class);
                    Expression expression = new DepartPermitionHandler().addPermition(roleAdded, deptPermission);
                    return expression;
                }).findAny().orElse(where);
        return expression1;


    }
}
